﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using Newtonsoft.Json;

namespace SocketServer
{
    class SocketServer
    {
        static Socket socket;
        static ReceiveDataUnpack messageHandle;

        private static ConcurrentQueue<String> queue;
        private static ConcurrentQueue<String> onlineListQueue;
        private static ConcurrentQueue<String> historyMessageQueue;
        private static ConcurrentQueue<String> userMapQueue;

        private static ConcurrentDictionary<Socket,int> socketDictionary;
        private static ConcurrentDictionary<int, String> onlineList;
        private static ConcurrentDictionary<int, String> userMap;
        private static List<Socket> userList;
        
        private static List<String> userMessagesList;

        private static Data data;
        
        private static bool isNewClient = false;
        private static bool isDelClient = false;
        
        static void Main(string[] args)
        {
            
            messageHandle= new ReceiveDataUnpack();
            
            queue = new ConcurrentQueue<String>();
            onlineListQueue = new ConcurrentQueue<String>();
            historyMessageQueue = new ConcurrentQueue<String>();
            userMapQueue = new ConcurrentQueue<String>();
            
            socketDictionary = new ConcurrentDictionary<Socket, int>();
            onlineList=new ConcurrentDictionary<int, string>();
            userMap=new ConcurrentDictionary<int, string>();
            userList=new List<Socket>();
            
            data = new Data();
            
            userMessagesList=new List<string>();
            
            initialization();

        }

        private static void initialization()
        {
            int port = 2333;
            String ip = "127.0.0.1";
            IPAddress address = IPAddress.Parse(ip);
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint endPoint = new IPEndPoint(address, port);
            socket.Bind(endPoint);
            socket.Listen(10);
            Thread waitClient = new Thread(WaitClient);
            waitClient.Start();
        }

        private static void WaitClient()
        {
            while (true)
            {
                Socket clientScoket = socket.Accept();
                
                Thread receiveclient = new Thread(ReceiveClient);
                receiveclient.Start(clientScoket);
            }
        }

        private static void SendClient(object socket)
        {
            Socket clientScoket = (Socket) socket;
            if (isNewClient)
            {
                OnlineListTojson();
                while (!onlineListQueue.IsEmpty)
                {
                    onlineListQueue.TryDequeue(out String message);
                    foreach(var i in userList)
                    {
                        Thread.Sleep(100);
                        i.Send(TCPpackage.wrap(message));
                        Console.WriteLine("向client发送在线列表：{0}", message);
                    }

                }

                UserMapTojson();
                while (!userMapQueue.IsEmpty)
                {
                    userMapQueue.TryDequeue(out String message);
                    foreach(var i in userList)
                    {
                        Thread.Sleep(100);
                        i.Send(TCPpackage.wrap(message));
                        Console.WriteLine("向client发送用户匹配表：{0}", message);
                    }

                }
                
                SendHistoryMessage(clientScoket);
                isNewClient = false;
            }
            
            else
            {
                while (!queue.IsEmpty)
                {
                    queue.TryDequeue(out String message);
                    foreach(var i in userList)
                    {
                        Thread.Sleep(100);
                        i.Send(TCPpackage.wrap(message));
                       Console.WriteLine("向client发送聊天内容：{0}", message);
                    }
                }
            }
        }

             
        private static void SendHistoryMessage(object socket)
        {
            Socket clientScoket = (Socket) socket;
            foreach (String message in userMessagesList)
            {
                historyMessageQueue.Enqueue(message);
            }

            while (!historyMessageQueue.IsEmpty)
            {
                historyMessageQueue.TryDequeue(out String message);
                clientScoket.Send(TCPpackage.wrap(message));
               Console.WriteLine("向client发送历史聊天：{0}", message);
            }
        }






        

        private static void ReceiveClient(object socket)
        {
            Socket clientScoket = (Socket) socket;
            bool isAbort = false;
            while (!isAbort)
            {
                 int datanum =clientScoket.Receive(messageHandle.DataBuffer);

                try
                {
                    messageHandle.ReadMessage(datanum);
                }
                catch (Exception e)
                {
                    socketDictionary.TryGetValue(clientScoket,out int id);
                    onlineList.TryRemove(id,out String value);
                    if (userList.Exists(t => t == clientScoket))
                    {
                        userList.Remove(clientScoket);
                    }
                    Console.WriteLine("client{0}关闭",id);
                    SendOfflineListTojson(id);
                    isAbort = true;
                }

                if (messageHandle.isRead)
                {
                     //反序列化解析到data
                    Data receiveData = JsonConvert.DeserializeObject<Data>(messageHandle.ReceiveStr);
                    messageHandle.SetDefault();

                    if (receiveData.name!=null && receiveData.id==-1 && receiveData.content==null)
                    {
                        isNewClient = true;
                        
                        //填写了用户名称后才算真正登录
                        userList.Add(clientScoket);
                        //客户端连接后存入socket字典中，键为socket，值为分配的id
                        socketDictionary.TryAdd(clientScoket,userMap.Count);
                        
                        //接收用户名称，并根据Socket在socketDictionary中找到id
                        int id;
                        socketDictionary.TryGetValue(clientScoket, out id);


                        userMap.TryAdd(id, receiveData.name);
                        //知道id后，从反序列化中中拿出name，存入onlinList(在线列表）
                        if (!onlineList.ContainsKey(id))//判断是否有存在，避免存入冲突
                        {
                            onlineList.TryAdd(id,receiveData.name);
                        }
                        Console.WriteLine("用户名称：{0}",receiveData.name);

                    }
                    
                    //客户端只发送内容
                    else if (receiveData.name == null && receiveData.id ==-1 && receiveData.content != null)
                    {
                        //接收用户名称，并根据Socket在socketDictionary中找到id
                        int id;
                        socketDictionary.TryGetValue(clientScoket, out id);
                        //知道id后，从反序列化中中拿出content，转成带有id和content的Json
                        ContentTojson(id,receiveData.content);
                        Console.WriteLine("接收内容：{0}",receiveData.content);
                    }
                    
                    
                    Thread sendClient =new Thread(SendClient);
                    sendClient.Start(clientScoket);
                }
            }
        }


        private static void OnlineListTojson()
        {
            foreach (var i in onlineList)
            {
                onlineList.TryGetValue(i.Key, out String name);
                data.id = i.Key;
                data.name = name;
                string jsonData = JsonConvert.SerializeObject(data);
                onlineListQueue.Enqueue(jsonData);
                DataClear();
            }
        }
        
        private static void UserMapTojson()
        {
            for (int i = 0; i < userMap.Count; i++)
            {
                userMap.TryGetValue(i, out String name);
                data.id = i;
                data.name = name;
                data.kind = 1;
                string jsonData = JsonConvert.SerializeObject(data);
                userMapQueue.Enqueue(jsonData);
                DataClear();
            }
        }
        
        private static void SendOfflineListTojson(int InId)
        {
            data.id = InId;
            string jsonData = JsonConvert.SerializeObject(data);
            onlineListQueue.Enqueue(jsonData);

            onlineListQueue.TryDequeue(out String message);
            for (int i = 0; i < userList.Count; i++) 
            {
                Thread.Sleep(10);
                userList[i].Send(TCPpackage.wrap(message));
                Console.WriteLine("向client{0}发送下线通知{1}",i,message); 
            }
        }

        private static void ContentTojson(int Inid, String InContent)
        {
            data.time=DateTime.Now.ToLocalTime().ToString();
            data.id = Inid;
            data.content = InContent;
            string jsonData = JsonConvert.SerializeObject(data);
            queue.Enqueue(jsonData);
            userMessagesList.Add(jsonData);
            DataClear();
        }

        private static void DataClear()
        {
            data.id = -1;
            data.name = null;
            data.content = null;
            data.time = null;
            data.kind = 0;
        }



    }
}